#pragma once
#include<iostream>
#include<string>
#include<cerrno>
#include<cstring>
#include<cstdlib>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<functional>
#include"Log.hpp"
#include"InetAddr.hpp"

enum    
{
    SOKCET_ERROR = 1,
    BIND_ERROT,
    USAGE_ERROR
};
const static int defaultfd = -1;
using hander_message_t = std::function<void(int sockfd,const std::string message,const InetAddr who)>;

class Udpserver
{
    public:
    Udpserver(uint16_t port,hander_message_t hander_message)
    :_sockfd(defaultfd)
    ,_port(port)
    ,_isrunning(false)
    ,_hander_message(hander_message)
    {}
    //初始化服务端
    void InitServer()
    {
        //创建udpsocket套接字
        //sockfd全双工
        _sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
           LOG(FATAL,"socket error,%s %d\n",strerror(errno),errno);
            exit(SOKCET_ERROR);
        }
        //成功
        LOG(INFO,"socket create success,sockfd:%d\n",_sockfd);
        // 填充sockaddr_in结构
        struct sockaddr_in local;
        //初始化
        bzero(&local,sizeof(local));

        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n  = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
           LOG(FATAL,"bind error %s %d\n",strerror(errno),errno);
            exit(BIND_ERROT);
        }
        //成功
        LOG(INFO,"socket bind success\n");
    }

    void Start()
    {
        //所有服务器，本质解决的是输入输出的问题，不想让网络通信模块业务模块进行强耦合
        _isrunning = true;
        while (true)
        {
            char message[1024];
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            //先收数据
            ssize_t n = recvfrom(_sockfd,message,sizeof(message)-1,0,(struct sockaddr*)&peer,&len);
            if(n>0)
            {
                message[n] = 0;
                InetAddr addr(peer);
                LOG(DEBUG,"get message from [%s:%d]: %s\n",addr.Ip().c_str(),addr.Port(),message);
;                _hander_message(_sockfd,message,addr);
            }
        }
        _isrunning = false;
    }
    ~Udpserver()
    {}
    private:
    int _sockfd;
    uint16_t _port;
    bool _isrunning;

hander_message_t _hander_message;
};